using System;
using System.Collections.Generic;
using System.Text;
using FlatRedBall;
using FlatRedBall.Input;
using FlatRedBall.AI.Pathfinding;
using FlatRedBall.Graphics.Animation;
using FlatRedBall.Graphics.Particle;

using FlatRedBall.Math.Geometry;
using FlatRedBall.Math.Splines;
using BitmapFont = FlatRedBall.Graphics.BitmapFont;
using Cursor = FlatRedBall.Gui.Cursor;
using GuiManager = FlatRedBall.Gui.GuiManager;

#if FRB_XNA || SILVERLIGHT
using Keys = Microsoft.Xna.Framework.Input.Keys;
using Vector3 = Microsoft.Xna.Framework.Vector3;
using Texture2D = Microsoft.Xna.Framework.Graphics.Texture2D;


#endif

using Gnome.Screens;

namespace Gnome.Entities
{
	public partial class Shadow
	{
        private int MAX_DIRECTION_TIME = 90;
        private int MAX_ONSCREEN_TIME = 1200;
        private int MAX_OFFSCREEN_TIME = 60;
        private int POSSIBLE_DIRECTION_CHANGES = 6;
        public static List<int> SHADOW_RESOLUTIONS = new List<int> { 325, 275, 225 };
        private float SHADOW_RESIZE_FRAMES = 25f;

        float xDir = 1;
        float yDir = 0;

        float changeDirTimer = 0;
        float leaveScreenTimer = 0;
        float offScreenTimer = 0;

        bool movingOnScreen = false;
        public bool isDead = false;
        public bool isPaused = false;

        public int timeToFlap = FlatRedBallServices.Random.Next(45);
        public int currentTime = 0;

        private AxisAlignedRectangle boundary = new AxisAlignedRectangle((float)LevelBase.SCREEN_WIDTH / 2, (float)LevelBase.SCREEN_HEIGHT / 2);

		private void CustomInitialize()
		{
            adjustDirection();
            setScaleTarget(SHADOW_RESOLUTIONS[0]);
            ShadowSprite.ScaleX = scaletarget;
            ShadowSprite.ScaleY = scaletarget;
            offScreenTimer = FlatRedBallServices.Random.Next(MAX_OFFSCREEN_TIME);
            ShadowSprite.Alpha = 0.3f;
            //The shadow's collision box was designed for 800x600 resolution. However, resizing to 1024x768
            //scaled the shadows differently than the boxes. This is a resize to fix this.
            CollisionBox.ScaleBy(600f / 768);
		}
        

		private void CustomActivity()
		{
            // if the player is dead, freeze all activity
            if (isDead)
                return;
            if (isPaused)
            {
                return;
            }
            // make the flap animation play only once
            if (ShadowSprite.JustCycled)
            {
                ShadowSprite.CurrentChainIndex = 0;
            }
            if (currentTime > timeToFlap)
            {
                ShadowSprite.CurrentChainIndex = 1;
                int temp = FlatRedBallServices.Random.Next(270);
                if (temp < 180)
                    timeToFlap = 180;
                else
                    timeToFlap = temp;
                currentTime = 0;
            }
            else
                currentTime++;

            X += xDir * moveSpeed * TimeManager.SecondDifference;
            Y += yDir * moveSpeed * TimeManager.SecondDifference;

            
            //If the bird has spent enough time offscreen, send it back.
            if(!isOnScreen())
            {
                if(offScreenTimer > MAX_OFFSCREEN_TIME && movingOnScreen == false)
                {
                    leaveScreenTimer = 0;
                    moveOnScreen();
                }
                offScreenTimer += TimeManager.SecondDifference * 30;
            }
            else
            {
                if (offScreenTimer != 0)
                {
                    offScreenTimer = 0;
                    movingOnScreen = false;
                }
                //If the bird is on screen and wants to get off screen, head off screen.
                if (leaveScreenTimer > MAX_ONSCREEN_TIME)
                {
                    changeDirTimer = 0;
                }
                else if (changeDirTimer > MAX_DIRECTION_TIME)
                {
                    adjustDirection();
                    changeDirTimer = FlatRedBallServices.Random.Next(50);
                }
                else
                {
                    changeDirTimer += TimeManager.SecondDifference * 30;
                    leaveScreenTimer += TimeManager.SecondDifference * 30;
                    checkEdges();
                }
            }


            //Scale down is we should scale down.
            if (ShadowSprite.ScaleX > scaletarget)
            {
                ShadowSprite.ScaleXVelocity = (SHADOW_RESOLUTIONS[1] - SHADOW_RESOLUTIONS[0]) / SHADOW_RESIZE_FRAMES;
                ShadowSprite.ScaleYVelocity = (SHADOW_RESOLUTIONS[1] - SHADOW_RESOLUTIONS[0]) / SHADOW_RESIZE_FRAMES;
                ShadowSprite.AlphaRate = 9f/SHADOW_RESIZE_FRAMES;
            }
            else
            {
                ShadowSprite.ScaleXVelocity = 0;
                ShadowSprite.ScaleYVelocity = 0;
                ShadowSprite.AlphaRate = 0;
            }
            
		}

        private bool isOnScreen()
        {
            if (CollisionBox.CollideAgainst(boundary))
                return true;
            else
                return false;
        }

        private void adjustDirection()
        {
            //Pick whether to turn left or right. 
            //If the bird is near one side of the screen, it should turn away from that side.
            //Otherwise, pick at random.(Arbitrary: 0 = go left, 1 = go right)
            int leftorright;
            if (X > SpriteManager.Camera.AbsoluteRightXEdgeAt(0) - ShadowSprite.ScaleX)
            {
                if (yDir > 0)
                    leftorright = 0;
                else if (yDir < 0)
                    leftorright = 1;
                else
                    leftorright = FlatRedBallServices.Random.Next(2);
            }
            else if (X < SpriteManager.Camera.AbsoluteLeftXEdgeAt(0) + ShadowSprite.ScaleX)
            {
                if (yDir < 0)
                    leftorright = 0;
                else if (yDir > 0)
                    leftorright = 1;
                else
                    leftorright = FlatRedBallServices.Random.Next(2);
            }
            else if (Y > SpriteManager.Camera.AbsoluteTopYEdgeAt(0) - ShadowSprite.ScaleY)
            {
                if (xDir < 0)
                    leftorright = 0;
                else if (xDir > 0)
                    leftorright = 1;
                else
                    leftorright = FlatRedBallServices.Random.Next(2);
            }
            else if (Y < SpriteManager.Camera.AbsoluteBottomYEdgeAt(0) + ShadowSprite.ScaleY)
            {
                if (xDir > 0)
                    leftorright = 0;
                else if (xDir < 0)
                    leftorright = 1;
                else
                    leftorright = FlatRedBallServices.Random.Next(2);
            }
            else
                leftorright = FlatRedBallServices.Random.Next(2);

            //Pick an angle to adjust course by (within a range of 0-MAX_DIRECTION_CHANGE)
            int changeincrement = FlatRedBallServices.Random.Next(4, POSSIBLE_DIRECTION_CHANGES + 4);
            double changevector = Math.PI / changeincrement;
            //Apply this angle to the bird's current rotation.
            //Just to be sure, make sure the rotations aren't going to overflow.
            if (RotationZ + changevector > float.MaxValue)
                leftorright = 1;
            if (RotationZ - changevector < float.MinValue)
                leftorright = 0;
            double newvector;
            if (leftorright == 0)
                newvector = RotationZ + changevector;
            else
                newvector = RotationZ - changevector;

            //Adjust the xDir and yDir to match the new vector
            xDir = (float)Math.Cos(newvector + Math.PI/2);
            yDir = (float)Math.Sin(newvector + Math.PI/2);
            RotationZ = (float)newvector;
        }

        /*Checks to see if the shadow is colliding with the edge of the screen, and handles it accordingly
         */
        private void checkEdges()
        {
            if ((X > SpriteManager.Camera.AbsoluteRightXEdgeAt(0) - ShadowSprite.ScaleX * 0.5 && xDir > 0)
                || (X < SpriteManager.Camera.AbsoluteLeftXEdgeAt(0) + ShadowSprite.ScaleX * 0.5 && xDir < 0))
            {
                xDir = 0;
                if (yDir > 0)
                {
                    yDir = 1;
                    RotationZ = 0;
                }
                else if (yDir < 0)
                {
                    yDir = -1;
                    RotationZ = (float)Math.PI;
                }
                else
                {
                    if (Y > 0)
                    {
                        yDir = -1;
                        RotationZ = (float)Math.PI;
                    }
                    else
                    {
                        yDir = 1;
                        RotationZ = 0;
                    }
                }
                if (X > 0)
                    X -= 1;
                else
                    X += 1;
            }
            if ((Y > SpriteManager.Camera.AbsoluteTopYEdgeAt(0) - ShadowSprite.ScaleX * 0.5 && yDir > 0)
                || (Y < SpriteManager.Camera.AbsoluteBottomYEdgeAt(0) + ShadowSprite.ScaleX * 0.5 && yDir < 0))
            {
                yDir = 0;
                if (xDir > 0)
                {
                    xDir = 1;
                    RotationZ = (float)(3 * Math.PI) / 2;
                }
                else if (xDir < 0)
                {
                    xDir = -1;
                    RotationZ = (float)Math.PI / 2;
                }
                else
                {
                    if (X > 0)
                    {
                        xDir = -1;
                        RotationZ = (float)Math.PI / 2;
                    }
                    else
                    {
                        xDir = 1;
                        RotationZ = (float)(3 * Math.PI) / 2;
                    }
                }
                if (Y > 0)
                    Y -= 1;
                else
                    Y += 1;
            }
        }

        public void setScaleTarget(int pixelsize)
        {
            scaletarget = .5f * pixelsize / SpriteManager.Camera.PixelsPerUnitAt(this.Z);
        }

        /* Place the shadow at a random point off screen, then set its path to move onto the screen
         */
        public void moveOnScreen()
        {
            movingOnScreen = true;
            //Randomly choose which side of the screen for the shadow to start on
            // 0 = top, 1 = bottom, 2 = right, 3 = left
            int startingside = FlatRedBallServices.Random.Next(0, 4);
            if (startingside == 0)
            {
                Y = (float)((LevelBase.SCREEN_HEIGHT / 2) + (ShadowSprite.ScaleY * 0.5));
                if (!GlobalData.is2P)
                {
                    int xwidth = (int)(Math.Round((LevelBase.SCREEN_WIDTH + ShadowSprite.ScaleX) / 2));
                    X = (float)FlatRedBallServices.Random.Next(-xwidth, 0);
                }
                else
                {
                    int xwidth = (int)(Math.Round(LevelBase.SCREEN_WIDTH / 4));
                    X = (float)FlatRedBallServices.Random.Next(-xwidth, xwidth);
                }
            }
            else if (startingside == 1)
            {
                Y = (float)(-(LevelBase.SCREEN_HEIGHT / 2) - (ShadowSprite.ScaleY * 0.5));
                int xwidth = (int)(Math.Round((LevelBase.SCREEN_WIDTH + ShadowSprite.ScaleX)/2));
                X = (float)FlatRedBallServices.Random.Next(-xwidth, xwidth);
            }
            else if (startingside == 2)
            {
                X = (float)((LevelBase.SCREEN_WIDTH / 2) + (ShadowSprite.ScaleX * 0.5));
                int yheight = (int)(Math.Round((LevelBase.SCREEN_HEIGHT + ShadowSprite.ScaleY) / 2));
                Y = (float)FlatRedBallServices.Random.Next(-yheight, 0);
            }
            else
            {
                X = (float)(-(LevelBase.SCREEN_WIDTH / 2) - (ShadowSprite.ScaleX * 0.5));
                if (!GlobalData.is2P)
                {
                    int yheight = (int)(Math.Round((LevelBase.SCREEN_HEIGHT + ShadowSprite.ScaleY) / 2));
                    Y = (float)FlatRedBallServices.Random.Next(-yheight, yheight);
                }
                else
                {
                    int yheight = (int)(Math.Round((LevelBase.SCREEN_HEIGHT + ShadowSprite.ScaleY) / 2));
                    Y = (float)FlatRedBallServices.Random.Next(-yheight, 0);
                }
            }
            double conversionfactor = Math.Sqrt((X * X) + (Y * Y));
            xDir = (float)(-X / conversionfactor);
            yDir = (float)(-Y / conversionfactor);
            //Set rotation
            if (startingside == 0)
            {
                RotationZ = (float)(Math.Asin(xDir) + Math.PI);
            }
            else if (startingside == 1)
            {
                RotationZ = -(float)Math.Asin(xDir);
            }
            else if (startingside == 2)
            {
                RotationZ = (float)Math.Acos(yDir);
            }
            else
            {
                RotationZ = -(float)Math.Acos(yDir);
            }
        }

        public void setScaleVelocity(float vel)
        {
            ShadowSprite.ScaleXVelocity = vel;
            ShadowSprite.ScaleYVelocity = vel;
        }

		private void CustomDestroy()
		{
            

		}

        private static void CustomLoadStaticContent(string contentManagerName)
        {


        }
	}
}
